#include "multprocessor.h"

MultProcessor::MultProcessor(int width, int height)
{

  links = new LinksList();

  columns = width;
  rows = height;
  
  processorMatrix = new Processor*[width];

  for(int loop = 0; loop < width; loop++)
  {
    processorMatrix[loop] = new Processor[height];
  }

  SetPhysicalLinks();

  std::cout << "Multi Processor Matrix Created" << std::endl;
}

MultProcessor::~MultProcessor(void)
{
  for(int loop = 0; loop < columns; loop++)
  {
    delete [] processorMatrix[loop];
  }

  delete links;
}

void MultProcessor::SetPhysicalLinks(void)
{
  bool * linkBuff[8];

  // set links for top row
  for(int loop = 0; loop < columns; loop++)
  {
    // create physical links
    for(int linkLoop = 0; linkLoop < 8; linkLoop++)
    {
      linkBuff[linkLoop] = links->CreateNewLink();
    }

    processorMatrix[loop][0].SetPhysicalLinks(linkBuff);
    processorMatrix[loop][0].SetAddress(loop + 1);

  }

  for(int y = 1; y < rows; y++)
  {
    for(int x = 0; x < columns; x++)
    {
      // filter how we need to populate NORTHWEST and WEST link
      if(0 == x)
      {
        // populate NORTHWEST link
        linkBuff[2] = links->CreateNewLink();
        // populate WEST link
        linkBuff[7] = links->CreateNewLink();
      }
      else // get western links
      {
        // get NORTHWEST link
        linkBuff[2] = processorMatrix[x - 1][y - 1].GetSouthEastLink();
        // get WEST link
        linkBuff[7] = processorMatrix[x - 1][y].GetEastLink();
      }

      // get NORTH link 
      linkBuff[0] = processorMatrix[x][y - 1].GetSouthLink();
      
      // filter if we how we need to populate NORTHEAST link
      if((columns - 1) == x)
      {
        linkBuff[1] = links->CreateNewLink();
      }
      else
      {
        linkBuff[1] = processorMatrix[x + 1][y - 1].GetSouthWestLink();
      }

      // create SOUTH link
      linkBuff[3] = links->CreateNewLink();
      // create SOUTHEAST link
      linkBuff[4] = links->CreateNewLink();
      // create SOUTHWEST link
      linkBuff[5] = links->CreateNewLink();
      // create EAST link
      linkBuff[6] = links->CreateNewLink();

      // Need to assign address first before trying to process anything
      processorMatrix[x][y].SetAddress(x + (y * rows) + 1);
      // set physical links to processor
      processorMatrix[x][y].SetPhysicalLinks(linkBuff);

    }
  }
}

void MultProcessor::SetProcessorPixel(int x, int y, bool value)
{
  processorMatrix[x][y].SetPixel(value);
}

bool MultProcessor::AreAllProcessorsComplete(void)
{
  bool complete = 1;

  for(int y = 0; y < rows; y++)
  {
    for(int x = 0; x < columns; x++)
    {
      complete &= processorMatrix[x][y].ProcessorComplete();
    }
  }

  return complete;
}

void MultProcessor::ClockAllProcessors(void)
{
  for(int y = 0; y < rows; y++)
  {
    for(int x = 0; x < columns; x++)
    {
      processorMatrix[x][y].ClockProcessor();
    }
  }
}

void MultProcessor::PrintProcessorBuildLabels(void)
{
  for(int y = 0; y < rows; y++)
  {
    for(int x = 0; x < columns; x++)
    {
      std::cout << processorMatrix[x][y].GetFinalLabel() << " ";
    }
    std::cout << std::endl;
  }
}

void MultProcessor::PrintProcessorPixels(void)
{
  for(int y = 0; y < rows; y++)
  {
    for(int x = 0; x < columns; x++)
    {
      std::cout << processorMatrix[x][y].GetPixelValue() << " ";
    }
    std::cout << std::endl;
  }
}




